package com.my.main.base.impnexp;

import com.my.main.base.exception.MyException;
import com.my.main.common.utils.DateUtil;
import com.my.main.common.utils.PinyinUtil;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class ExcelExpUtil  extends ExcelUtil {

	private static final String SERVICE_EXCEL_EXPPATH = "/newlife/exp/excel";
	
	/**
	 * Excel导出工具
	 *
	 * @param poList		po对象列表
	 * @param clazz
	 * @param title
	 * @param rootRealPath
	 * @return
	 */
	public <T> ExcelErrorMesg isExpSuccess(List<T> poList, Class clazz, String title, String rootRealPath) {

		try {
			return writeExcel(poList, clazz, title, rootRealPath);
		}
		catch (MyException e) {
			e.printStackTrace();
			logger.error(e);
			return new ExcelErrorMesg(false, 2, e.getMessage(), null, null);
		}
		catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
			return new ExcelErrorMesg(false, 2, "执行时出现异常", null, null);
		}

	}




	/**
	 * 获取该对象的所有属性及其对应的值
	 * @param obj
	 * @return
	 */
	 Map<String, ExcelCell> getCells(Object obj) {

        Map<String, ExcelCell> excelCellMap = new HashMap<String, ExcelCell>();

        try {
	        // 得到类对象
	        Class clazz = (Class)obj.getClass();
	        // 得到类中的所有属性集合
	        Field[] fileArray = clazz.getDeclaredFields();
	        for (int i=0; i<fileArray.length; i++) {
	            Field field = fileArray[i];
	            field.setAccessible(true); 							// 设置此属性是可以访问的

	            // 有注解读取，没有注解忽略
	            PoExcelAnnotation ann = field.getAnnotation(PoExcelAnnotation.class);
	            if (ann != null) {
	            	Object val = field.get(obj);
	            	ExcelCell cell = new ExcelCell(val, ann.title(), ann.codeType());
	            	excelCellMap.put(field.getName(), cell);		// 设置单元格信息
	            }
	        }
        }
        catch (IllegalAccessException e) {
			logger.error(e);
			throw new MyException("读取属性数据时出现安全权限参数异常");
        }
        catch (IllegalArgumentException e) {
			logger.error(e);
			throw new MyException("读取属性数据时出现参数异常");
        }
        catch (Exception e) {
        	 e.printStackTrace();
        	logger.error(e);
        	throw new MyException("读取属性数据时出现异常");
        }

        return excelCellMap;

    }


	/**
	 * 将一组List集合转化为excel文件
	 *
	 * @param tList
	 * @param title
	 * @param rootRealPath
	 * @throws Exception
	 */
	private <T> ExcelErrorMesg writeExcel(List<T> tList, Class clazz, String title, String rootRealPath) {

		FileOutputStream output = null;
//		HSSFWorkbook workbook = new HSSFWorkbook();			// 这个对象用来打开或者创建Excel文件对象，一个Excel文件对应一个该对象

		//XSSFWorkbook是Excel2007版的导出类，该版本Excek最大支持104万条数据，以xlsx后缀
		XSSFWorkbook workbook1 = new XSSFWorkbook();
		//提高导出效率的类
		SXSSFWorkbook workbook = new SXSSFWorkbook(workbook1, 100);
		
		//      创建单元格，设置表头，表头居中

		try {
			

			// 获取表头文字
			List<ExcelCell> titleCellList = getCellTitle(clazz);
			
			// 将list集合po中的属性名与值全部取出存入map集合准备写入excel文件
			List<Map<String, ExcelCell>> dataCellMapList = new ArrayList<Map<String, ExcelCell>>();
			for(Object obj : tList) {
				// 取出属性名与值并添加
			   	Map<String, ExcelCell> map = getCells(obj);
			   	dataCellMapList.add(map);
			}
			
			// 开始生成Excel表格
			Integer index  = 0;												// 行序号
			Sheet sheet = workbook.createSheet(title);					// 这个对象用来代表一页excel表单，字符串参数为表单标题,通过这个对象生成excel中的数据
			List<Integer> timeFormat = new ArrayList<Integer>();		//存储第几条数据需要格式化时间
			List<Integer> numberFormat = new ArrayList<Integer>();		//存储为数字格式
			Map mapCls = getFieldClass(clazz.getName());	
			// 第一行设置为标题
			sheet.addMergedRegion(new CellRangeAddress(0, 0, 0,titleCellList.size()<=1? 1:titleCellList.size()-1));	// 这个方法用来合并单元格，4个参数分别为合并起始行，截至行，起始列， 截至列
			Row row = sheet.createRow(index++);							// 这个对象用来生成一行数据，根据int参数数据所在第几行
			Cell hc = row.createCell(0);
			hc.setCellValue(title);
			//居中样式
			CellStyle style = workbook.createCellStyle();
			style.setAlignment(HorizontalAlignment.CENTER);
			hc.setCellStyle(style);
			// 第2行为po属性名对应的注解里面的汉字title
			row = sheet.createRow(index++);
			for (int i=0; i<titleCellList.size(); i++) {
				if(mapCls.get(titleCellList.get(i).getName()).equals(Date.class)) {
					timeFormat.add(i);
				}
				row.createCell(i).setCellValue(titleCellList.get(i).getTitle());
			}
			
			//判断是否为数字
			for (int i=0; i<titleCellList.size(); i++) {
				if(mapCls.get(titleCellList.get(i).getName()).equals(BigDecimal.class)) {
					numberFormat.add(i);
				}
				row.createCell(i).setCellValue(titleCellList.get(i).getTitle());
			}
			
			// 从第3行开始
			// 循环生成数据
			for (Map<String, ExcelCell> dataCellMap : dataCellMapList) {
				row = sheet.createRow(index++);
				int i = 0;
				for(ExcelCell titleCell : titleCellList) {
					boolean flag = false;
					boolean numFlag = false;
					for(Integer ibol : timeFormat) {
						if(i==ibol) {
							flag = true;
							break;
						}
					}
					
					for(Integer inum : numberFormat) {
						if(i==inum) {
							numFlag = true;
							break;
						}
					}
					
					Object ob = dataCellMap.get(titleCell.getName()).getVal();
					if(flag) {			
						row.createCell(i).setCellValue(ob==null? "(空)" :new SimpleDateFormat(TIMEFORMAT).format(ob));
					}else{
						row.createCell(i).setCellValue(ob==null? "(空)" :""+dataCellMap.get(titleCell.getName()).getVal());
					}
					
					if(numFlag) {
						row.createCell(i).setCellValue(ob==null? 0.00 :Double.parseDouble(ob.toString()));
					}
					
					numFlag = false;
					flag = false;
					i++;
				}
			}
			
			String formatDate = DateUtil.getFormatDate("yyyyMMddHHmmss");

			// 保存路径
			String newFileUrl = SERVICE_EXCEL_EXPPATH + "/" + PinyinUtil.ToFirstChar(title) + formatDate +".xlsx";
//			String newFileUrl = Configure.SERVICE_EXCEL_EXPPATH + "/" + title + formatDate +".xlsx";
			File file = new File((rootRealPath + newFileUrl).substring(0,(rootRealPath + newFileUrl).lastIndexOf("/")));
			if(!file.exists()) {
				file.mkdirs();
			}
			output = new FileOutputStream(rootRealPath + newFileUrl);
			workbook.write(output);
			output.flush();
			
			return new ExcelErrorMesg(true, 1, "导出成功", newFileUrl, rootRealPath+newFileUrl);
		}
		catch(MyException e) {
			e.printStackTrace();
			logger.error(e);
			throw new MyException(e.getMessage());
		}
		catch (FileNotFoundException e) {
			e.printStackTrace();
			logger.error(e);
			throw new MyException("文件生成失败");
		} 
		catch (IOException e) {
			logger.error(e);
			throw new MyException("文件写入时出现流错误");
		}
		catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
			throw new MyException("文件写入时出现异常");
		}
		finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					logger.error(e);
				}
			}
			try {
				workbook.close();
			} catch (IOException e) {
				logger.error(e);
			}
		}
		
	}
	
	
	/**
	 * Excel导出工具(单列,分录)
	 * 说明：   需要分录的字段，在该单元格里存一个相应的List<String>
	 * 如：      titleCell.getName()="车系" titleCell.getName().val()=[亚洲龙,皇冠,皇冠,海狮]	titleCell.getName()="车型编码"	titleCell.getName().val()=[A5MB,E2A1 E2A5,E2A1 E2A5,A7]
	 * @param poList		po对象列表
	 * @param clazz
	 * @param title
	 * @param rootRealPath
	 * @author ysy 191119
	 * @return
	 */
	public <T> ExcelErrorMesg isExpSuccessWithSplit(List<T> poList, Class clazz, String title, String rootRealPath) {
		
		try {
			return writeExcelWithSplit(poList, clazz, title, rootRealPath);
		} 
		catch (MyException e) {
			e.printStackTrace();
			logger.error(e);
			return new ExcelErrorMesg(false, 2, e.getMessage(), null, null);
		}
		catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
			return new ExcelErrorMesg(false, 2, "执行时出现异常", null, null);
		}
		
	}
	
	
	/**
	 * 将一组List集合转化为excel文件(单列,分录)
	 * 
	 * @param tList
	 * @param title
	 * @param rootRealPath
	 * @throws Exception
	 * @author ysy 191119
	 */
	private <T> ExcelErrorMesg writeExcelWithSplit(List<T> tList, Class clazz, String title, String rootRealPath) {
		
		FileOutputStream output = null;
//		HSSFWorkbook workbook = new HSSFWorkbook();			// 这个对象用来打开或者创建Excel文件对象，一个Excel文件对应一个该对象
		
		//XSSFWorkbook是Excel2007版的导出类，该版本Excek最大支持104万条数据，以xlsx后缀
		XSSFWorkbook workbook1 = new XSSFWorkbook();
		//提高导出效率的类
		SXSSFWorkbook workbook = new SXSSFWorkbook(workbook1, 100);
		
		//      创建单元格，设置表头，表头居中

		try {
			

			// 获取表头文字
			List<ExcelCell> titleCellList = getCellTitle(clazz);
			
			// 将list集合po中的属性名与值全部取出存入map集合准备写入excel文件
			List<Map<String, ExcelCell>> dataCellMapList = new ArrayList<Map<String, ExcelCell>>();
			for(Object obj : tList) {
				// 取出属性名与值并添加
			   	Map<String, ExcelCell> map = getCells(obj);
			   	dataCellMapList.add(map);
			}
			
			// 开始生成Excel表格
			Integer index  = 0;												// 行序号
			Sheet sheet = workbook.createSheet(title);					// 这个对象用来代表一页excel表单，字符串参数为表单标题,通过这个对象生成excel中的数据
			List<Integer> timeFormat = new ArrayList<Integer>();		//存储第几条数据需要格式化时间
			List<Integer> numberFormat = new ArrayList<Integer>();		//存储为数字格式
			Map mapCls = getFieldClass(clazz.getName());	
			// 第一行设置为标题
			sheet.addMergedRegion(new CellRangeAddress(0, 0, 0,titleCellList.size()<=1? 1:titleCellList.size()-1));	// 这个方法用来合并单元格，4个参数分别为合并起始行，截至行，起始列， 截至列
			Row row = sheet.createRow(index++);							// 这个对象用来生成一行数据，根据int参数数据所在第几行
			Cell hc = row.createCell(0);
			hc.setCellValue(title);
			//居中样式
			CellStyle style = workbook.createCellStyle();
			style.setAlignment(HorizontalAlignment.CENTER);
			hc.setCellStyle(style);
			// 第2行为po属性名对应的注解里面的汉字title
			row = sheet.createRow(index++);
			for (int i=0; i<titleCellList.size(); i++) {
				if(mapCls.get(titleCellList.get(i).getName()).equals(Date.class)) {
					timeFormat.add(i);
				}
				row.createCell(i).setCellValue(titleCellList.get(i).getTitle());
			}
			
			//判断是否为数字
			for (int i=0; i<titleCellList.size(); i++) {
				if(mapCls.get(titleCellList.get(i).getName()).equals(BigDecimal.class)) {
					numberFormat.add(i);
				}
				row.createCell(i).setCellValue(titleCellList.get(i).getTitle());
			}
			
			
			// 从第3行开始
			// 循环生成数据
			for (Map<String, ExcelCell> dataCellMap : dataCellMapList) {
				
				int count = 1;
				// 获取分录行数		// 默认检索到的第一个存了List的字段，获取其size()
				for(ExcelCell titleCell : titleCellList) {
					Object ob = dataCellMap.get(titleCell.getName()).getVal();	
					if(ob instanceof ArrayList) {
						List<String> list = castList(ob, String.class);
						count = list.size();
						break;
					}
				}
				if (count > 1) {
					List<Integer> forMergeList = new ArrayList<Integer>();
					for (int j = 0; j < count; j++) {
						row = sheet.createRow(index);
						int i = 0;
						for(ExcelCell titleCell : titleCellList) {
							boolean flag = false;
							boolean numFlag = false;
							for(Integer ibol : timeFormat) {
								if(i==ibol) {
									flag = true;
									break;
								}
							}
							
							for(Integer inum : numberFormat) {
								if(i==inum) {
									numFlag = true;
									break;
								}
							}
							
							Object ob = dataCellMap.get(titleCell.getName()).getVal();									
							if(!(ob instanceof ArrayList)) {							
								if(flag) {			
									row.createCell(i).setCellValue(ob==null? "(空)" :new SimpleDateFormat(TIMEFORMAT).format(ob));
								}else{
									row.createCell(i).setCellValue(ob==null? "(空)" :""+dataCellMap.get(titleCell.getName()).getVal());
								}							
								if(numFlag) {
									row.createCell(i).setCellValue(ob==null? 0.00 :Double.parseDouble(ob.toString()));
								}
								if (!forMergeList.contains(i)) {
									forMergeList.add(i);
								}								
							} else {
								String item = castList(ob, String.class).get(j);
								if(flag) {			
									row.createCell(i).setCellValue(ob==null? "(空)" :new SimpleDateFormat(TIMEFORMAT).format(item));
								}else{
									row.createCell(i).setCellValue(ob==null? "(空)" :""+item);
								}				
								if(numFlag) {
									row.createCell(i).setCellValue(ob==null? 0.00 :Double.parseDouble(item));
								}
							}
							numFlag = false;
							flag = false;
							i++;
						}
						index = index + 1;
					}
					
					for (Integer forMerge : forMergeList) {
						sheet.addMergedRegion(new CellRangeAddress(
								index - count, //first row (0-based)
								index - 1, //last row  (0-based)
								forMerge, //first column (0-based)
								forMerge  //last column  (0-based)
						));
					}
					
				} else {
					row = sheet.createRow(index);
					int i = 0;
					for(ExcelCell titleCell : titleCellList) {
						boolean flag = false;
						boolean numFlag = false;
						for(Integer ibol : timeFormat) {
							if(i==ibol) {
								flag = true;
								break;
							}
						}
						
						for(Integer inum : numberFormat) {
							if(i==inum) {
								numFlag = true;
								break;
							}
						}
						
						Object ob = dataCellMap.get(titleCell.getName()).getVal();									
						if(!(ob instanceof ArrayList)) {							
							if(flag) {			
								row.createCell(i).setCellValue(ob==null? "(空)" :new SimpleDateFormat(TIMEFORMAT).format(ob));
							}else{
								row.createCell(i).setCellValue(ob==null? "(空)" :""+dataCellMap.get(titleCell.getName()).getVal());
							}							
							if(numFlag) {
								row.createCell(i).setCellValue(ob==null? 0.00 :Double.parseDouble(ob.toString()));
							}
						} else {
							String item = "";
							if (castList(ob, String.class).size() > 0 && castList(ob, String.class) != null) {
								item = castList(ob, String.class).get(0);
							}
							if(flag) {			
								row.createCell(i).setCellValue(ob==null? "(空)" :new SimpleDateFormat(TIMEFORMAT).format(item));
							}else{
								row.createCell(i).setCellValue(ob==null? "(空)" :""+item);
							}				
							if(numFlag) {
								row.createCell(i).setCellValue(ob==null? 0.00 :Double.parseDouble(item));
							}
						}
						numFlag = false;
						flag = false;
						i++;
					}
					index = index + 1;
				}
			}
			
			String formatDate = DateUtil.getFormatDate("yyyyMMddHHmmss");

			// 保存路径
			String newFileUrl = SERVICE_EXCEL_EXPPATH + "/" + PinyinUtil.ToFirstChar(title) + formatDate +".xlsx";
//			String newFileUrl = Configure.SERVICE_EXCEL_EXPPATH + "/" + title + formatDate +".xlsx";
			File file = new File((rootRealPath + newFileUrl).substring(0,(rootRealPath + newFileUrl).lastIndexOf("/")));
			if(!file.exists()) {
				file.mkdirs();
			}
			output = new FileOutputStream(rootRealPath + newFileUrl);
			workbook.write(output);
			output.flush();
			
			return new ExcelErrorMesg(true, 1, "导出成功", newFileUrl, rootRealPath+newFileUrl);
		}
		catch(MyException e) {
			e.printStackTrace();
			logger.error(e);
			throw new MyException(e.getMessage());
		}
		catch (FileNotFoundException e) {
			e.printStackTrace();
			logger.error(e);
			throw new MyException("文件生成失败");
		} 
		catch (IOException e) {
			logger.error(e);
			throw new MyException("文件写入时出现流错误");
		}
		catch (Exception e) {
			e.printStackTrace();
			logger.error(e);
			throw new MyException("文件写入时出现异常");
		}
		finally {
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					logger.error(e);
				}
			}
			try {
				workbook.close();
			} catch (IOException e) {
				logger.error(e);
			}
		}
		
	}



	/**  
	 *  18-6-8 新增方法,将2个list集合转化成excel文件
	 * @param list	表头集合
	 * @param list2	数据集合
	 * @return
	 */
//	public ExcelErrorMesg isExpSuccess(List<TaskRecordElement> list, List<TaskRecordElement> list2 ,String... title) {
//
//		try {
//			return writeExcel(list,list2,title);
//		} 
//		catch (MyException e) {
//			e.printStackTrace();
//			logger.error(e);
//			return new ExcelErrorMesg(false, 2, e.getMessage(), null, null);
//		}
//		catch (Exception e) {
//			e.printStackTrace();
//			logger.error(e);
//			return new ExcelErrorMesg(false, 2, "执行时出现异常", null, null);
//		}
//	}



	/**  
	 *  18-6-8 新增方法,将2个list集合转化成excel文件，不受类的限制
	 * @param list	表头集合
	 * @param list2	数据集
	 * @param 标题
	 * @return
	 */
//	private ExcelErrorMesg writeExcel(List<TaskRecordElement> list, List<TaskRecordElement> list2 ,String... title) {
//		FileOutputStream output = null;
//		HSSFWorkbook workbook = new HSSFWorkbook();						// 这个对象用来打开或者创建Excel文件对象，一个Excel文件对应一个该对象
//		//      创建单元格，设置表头，表头居中
//
//		try {
//			
//
//			// 开始生成Excel表格
//			Integer index  = 0;												// 行序号
//			HSSFSheet sheet = workbook.createSheet(title[0]);					// 这个对象用来代表一页excel表单，字符串参数为表单标题,通过这个对象生成excel中的数据
//			HSSFRow row = null;		
//			for(int i=0;i<title.length;i++) {
//				// 第一行设置为标题
//				if (i==0) {
//					sheet.addMergedRegion(new CellRangeAddress(index, index, 0,list.size()<=1? 1:list.size()-1));	// 这个方法用来合并单元格，4个参数分别为合并起始行，截至行，起始列， 截至列		
//				}
//				else {
//					sheet.addMergedRegion(new CellRangeAddress(index, index, 0,list.size()<=1? 1:(list.size()-1)/2));	// 这个方法用来合并单元格，4个参数分别为合并起始行，截至行，起始列， 截至列
//					
//				}
//				row = sheet.createRow(index++);							// 这个对象用来生成一行数据，根据int参数数据所在第几行
//				HSSFCell hc = row.createCell(0);
//				hc.setCellValue(title[i]);
//				//居中样式
//				HSSFCellStyle style = workbook.createCellStyle();
//				if (i==0) {
//					style.setAlignment(HorizontalAlignment.CENTER);
//				}
//				else {
//					style.setAlignment(HorizontalAlignment.LEFT);
//				}
//				
//				hc.setCellStyle(style);
//			}
//			
//			
//			// 第2行为po属性名对应的注解里面的汉字title
//			row = sheet.createRow(index++);
//			for (int i=0; i<list.size(); i++) {
//				row.createCell(i).setCellValue(list.get(i).getValue());
//			}
//			
//			// 从第3行开始
//			// 循环生成数据
//			int inde = 0;
//			for (TaskRecordElement t: list2) {			
//				if(inde==list.size() || inde==0) {
//					inde=0;
//					row = sheet.createRow(index++);
//				}
//				row.createCell(inde).setCellValue(t.getValue()==null || t.getValue().trim().equals("")? "(空)" :t.getValue());
//				inde++;
//			}
//
//			// 保存路径
//			String newFileUrl = Configure.SERVICE_Excel_ExpPath + "/" + StrUtil.getRandomNumberString(16)+".xls";
//			File file = new File((Configure.ROOT_RealPath + newFileUrl).substring(0,(Configure.ROOT_RealPath + newFileUrl).lastIndexOf("/")));
//			if(!file.exists()) {
//				file.mkdirs();
//			}
//			output = new FileOutputStream(Configure.ROOT_RealPath + newFileUrl);
//			workbook.write(output);
//			output.flush();
//			
//			return new ExcelErrorMesg(true, 1, "导出成功", newFileUrl, Configure.ROOT_RealPath+newFileUrl);
//		}
//		catch(MyException e) {
//			e.printStackTrace();
//			logger.error(e);
//			throw new MyException(e.getMessage());
//		}
//		catch (FileNotFoundException e) {
//			e.printStackTrace();
//			logger.error(e);
//			throw new MyException("文件生成失败");
//		} 
//		catch (IOException e) {
//			logger.error(e);
//			throw new MyException("文件写入时出现流错误");
//		}
//		catch (Exception e) {
//			e.printStackTrace();
//			logger.error(e);
//			throw new MyException("文件写入时出现异常");
//		}
//		finally {
//			if (output != null) {
//				try {
//					output.close();
//				} 
//				catch (IOException e) {
//					logger.error(e);
//				}
//			}
//		}
//	}
	
	
	/**
	 * Object类型转换List类型
	 * @param obj 需要转换的List对象
	 * @param clazz List中元素的class
	 * @author ysy 191119
	 * @return
	 */
	public static <T> List<T> castList(Object obj, Class<T> clazz) {
		List<T> result = new ArrayList<T>();
		if (obj instanceof List<?>) {
			for (Object o : (List<?>) obj) {
				result.add(clazz.cast(o));
			}
			return result;
		}
		return null;
	}

//	public static void main(String[] args) {
//		DispatchReason d1 = new DispatchReason(99L,"2",2,true,new Date(),99L,"8",new Date(),99L,"string");
//		DispatchReason d2 = new DispatchReason(100L,"2",2,true,new Date(),99L,"8",new Date(),99L,"string");
//		List<DispatchReason> list = new LinkedList<>();
//		list.add(d1);
//		list.add(d2);
//		System.out.println(list);
//		ExcelExpUtil a = new ExcelExpUtil();
//		a.isExpSuccess(list,DispatchReason.class,"11");
//	}
}

